<html>
<head>
<title>Deep Debugger</title>
<script>

var tableRows = {};
var tableCels = {};
var tableObjs = {};
var tablesBuilt = {};
var tableShows = {};
var tableHides = {};

// IE: nodes w/id need to be redeclared or getElementById is b0rked
var frame = null;

window.onload = function(){
	// if IE loads this page too quickly (instantly) then 
	// window.debugVar might not have been set
	window.setTimeout(startMeUp, 100);
}

function startMeUp(){
	frame = document.getElementById('frame');
	// GET string 
	var index = location.search.split("=").pop();
	var debugObj = window.opener.dojo.debugDeep;
	var debugVar = debugObj.debugVars[index] || window.debugVar;
	buildTable('root', frame, debugVar);
}

function buildTable(path, parent, obj){
	var keys = [];
	var vals = [];
	for(var prop in obj){
		keys.push(prop);
		try {
			vals[prop] = obj[prop];
		} catch(E) {
			vals[prop] = 'ERROR: ' + E.message;
		}
	}
	keys.sort(keySorter);

	if (!keys.length){

		var div = document.createElement('div');
		div.appendChild(document.createTextNode('Object has no properties.'));

		parent.appendChild(div);
		return;
	}


	var t = document.createElement('table');
	t.border = "1";

	var tb = document.createElement('tbody');
	t.appendChild(tb);


	for(var i = 0; i < keys.length; i++) {
		buildTableRow(path+'-'+keys[i], tb, keys[i], vals[keys[i]]);
	}

	if (path == 'root'){
		//t.style.width = '90%';
	}
	t.style.width = '100%';

	parent.appendChild(t);

	tablesBuilt[path] = true;
}

function buildTableRow(path, tb, name, value) {

	var simpleType = typeof(value);
	var createSubrow = (simpleType == 'object');
	var complexType = simpleType;

	if (simpleType == 'object'){
		var cls = getConstructorClass(value);
		if (cls){
			if (cls == 'Object'){
			}else if (cls == 'Array'){
				complexType = 'array';
			}else{
				complexType += ' ('+cls+')';
			}
		}
	}

/*var tr1 = document.createElement('tr');
	var td1 = document.createElement('td');
	var td2 = document.createElement('td');
	var td3 = document.createElement('td');
	var td4 = document.createElement('td');*/

	var row = tb.rows.length;
	var tr1 = tb.insertRow(row++);
	var td1 = tr1.insertCell(0);
	var td2 = tr1.insertCell(1);
	var td3 = tr1.insertCell(2);
	var td4 = tr1.insertCell(3);
	
	tr1.style.verticalAlign = 'top';
	td1.style.verticalAlign = 'middle';

	td1.className = 'propPlus';
	td2.className = 'propName';
	td3.className = 'propType';
	td4.className = 'propVal';

	//tr1.appendChild(td1);
	//tr1.appendChild(td2);
	//tr1.appendChild(td3);
	//tr1.appendChild(td4);

	if (createSubrow){
		var img1 = document.createElement('img');
		img1.width = 9;
		img1.height = 9;
		img1.src = 'arrow_show.gif';
		var a1 = document.createElement('a');
		a1.appendChild(img1);
		a1.href = '#';
		a1.onclick = function(){ showTableRow(path); return false; };

		var img2 = document.createElement('img');
		img2.width = 9;
		img2.height = 9;
		img2.src = 'arrow_hide.gif';
		var a2 = document.createElement('a');
		a2.appendChild(img2);
		a2.href = '#';
		a2.onclick = function(){ hideTableRow(path); return false; };
		a2.style.display = 'none';

		tableShows[path] = a1;
		tableHides[path] = a2;

		td1.appendChild(a1);
		td1.appendChild(a2);
	}else{
		var img = document.createElement('img');
		img.width = 9;
		img.height = 9;
		img.src = 'spacer.gif';

		td1.appendChild(img);
	}

	td2.appendChild(document.createTextNode(name));
	td3.appendChild(document.createTextNode(complexType));
	td4.appendChild(buildPreBlock(value));

	//tb.appendChild(tr1);

	if (createSubrow){
		var tr2 = tb.insertRow(row++);
		var td5 = tr2.insertCell(0);
		var td6 = tr2.insertCell(1);
		
		//var tr2 = document.createElement('tr');
		//var td5 = document.createElement('td');
		//var td6 = document.createElement('td');

		td5.innerHTML = '&nbsp;';
		//td6.innerHTML = '&nbsp;';

		td6.colSpan = '3';

		tr2.appendChild(td5);
		tr2.appendChild(td6);

		tr2.style.display = 'none';

		tb.appendChild(tr2);

		tableRows[path] = tr2;
		tableCels[path] = td6;
		tableObjs[path] = value;
	}
}

function showTableRow(path){

	var tr = tableRows[path];
	var td = tableCels[path];
	var a1 = tableShows[path];
	var a2 = tableHides[path];

	if (!tablesBuilt[path]){

		//alert('building table for '+path);
		buildTable(path, td, tableObjs[path]);
	}

	tr.style.display = 'table-row';

	a1.style.display = 'none';
	a2.style.display = 'inline';
}

function hideTableRow(path){

	var tr = tableRows[path];
	var a1 = tableShows[path];
	var a2 = tableHides[path];

	tr.style.display = 'none';

	a1.style.display = 'inline';
	a2.style.display = 'none';
}

function buildPreBlock(value){

	//
	// how many lines ?
	//

	var s = ''+value;
	s = s.replace("\r\n", "\n");
	s = s.replace("\r", "");
	var lines = s.split("\n");


	if (lines.length < 2){

		if (lines[0].length < 60){

			var pre = document.createElement('pre');
			pre.appendChild(document.createTextNode(s));
			return pre;
		}
	}


	//
	// multiple lines :(
	//

	var preview = lines[0].substr(0, 60) + ' ...';

	var pre1 = document.createElement('pre');
	pre1.appendChild(document.createTextNode(preview));
	pre1.className = 'clicky';

	var pre2 = document.createElement('pre');
	pre2.appendChild(document.createTextNode(s));
	pre2.style.display = 'none';
	pre2.className = 'clicky';

	pre1.onclick = function(){
		pre1.style.display = 'none';
		pre2.style.display = 'block';
	}

	pre2.onclick = function(){
		pre1.style.display = 'block';
		pre2.style.display = 'none';
	}

	var pre = document.createElement('div');

	pre.appendChild(pre1);
	pre.appendChild(pre2);

	return pre;
}

function getConstructorClass(obj){

	if (!obj.constructor || !obj.constructor.toString) return;

	var m = obj.constructor.toString().match(/function\s*(\w+)/);

	if (m && m.length == 2) return m[1];

	return null;
}

function keySorter(a, b){

	if (a == parseInt(a) && b == parseInt(b)){

		return (parseInt(a) > parseInt(b)) ? 1 : ((parseInt(a) < parseInt(b)) ? -1 : 0);
	}

	// sort by lowercase string

	var a2 = String(a).toLowerCase();
	var b2 = String(b).toLowerCase();

	return (a2 > b2) ? 1 : ((a2 < b2) ? -1 : 0);
}

</script>
<style>

body {
	font-family: arial, helvetica, sans-serif;
}

table {
	border-width: 0px;
	border-spacing: 1px;
	border-collapse: separate;
}

td {
	border-width: 0px;
	padding: 2px;
}

img {
	border: 0;
}

pre {
	margin: 0;
	padding: 0;
	white-space: -moz-pre-wrap;  /* Mozilla, supported since 1999 */
	white-space: -pre-wrap;      /* Opera 4 - 6 */
	white-space: -o-pre-wrap;    /* Opera 7 */
	white-space: pre-wrap;       /* CSS3 - Text module (Candidate Recommendation) http://www.w3.org/TR/css3-text/#white-space */
	word-wrap: break-word;       /* IE 5.5+ */
}

pre.clicky {
	cursor: hand;
	cursor: pointer;
}

td.propPlus {
	width: 9px;
	background-color: #ddd;
}

td.propName {
	background-color: #ddd;
}

td.propType {
	background-color: #ddd;
}

td.propVal {
	background-color: #ddd;
}

</style>
</head>
<body>

<h2>Javascript Object Browser</h2>

<div id="frame"></div>

</body>
</html>